package com.zhoug.player.exoplayer.v2;

import android.content.Context;
import android.net.Uri;
import android.view.TextureView;

import com.zhoug.player.core.utils.LogUtils;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.OptIn;
import androidx.media3.common.MediaItem;
import androidx.media3.common.PlaybackException;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.datasource.DefaultHttpDataSource;
import androidx.media3.exoplayer.DefaultRenderersFactory;
import androidx.media3.exoplayer.ExoPlayer;
import androidx.media3.exoplayer.hls.DefaultHlsExtractorFactory;
import androidx.media3.exoplayer.hls.HlsMediaSource;
import androidx.media3.exoplayer.util.EventLogger;
import androidx.media3.extractor.ts.DefaultTsPayloadReaderFactory;

/**
 * @author: zhoug
 * @since: 2025-06-20
 */
@OptIn(markerClass = UnstableApi.class)
public class ZExoPlayer {
    private static final String TAG = ">>>ZExoPlayer";

    private ExoPlayer mPlayer;

    /**
     * 上下文
     */
    private Context mContext;
    /**
     * 播放url
     */
    private Uri mPlayUrl;
    /**
     * 视频播放窗口
     */
    private TextureView mTextureView;

    public ZExoPlayer(@NonNull Context context) {
        this.mContext = context;
    }

    public ExoPlayer getPlayer() {
        return mPlayer;
    }

    /**
     * 视频播放窗口
     *
     * @param textureView 视频播放窗口
     */
    public void setVideoTextureView(@Nullable TextureView textureView) {
        mTextureView = textureView;
        if (mTextureView != null) {
            mTextureView.setKeepScreenOn(true);
        }
        if (mPlayer != null) {
            mPlayer.setVideoTextureView(textureView);
        }
    }


    /**
     * 播放url
     *
     * @param playUrl 播放url
     */
    public void setPlayUrl(Uri playUrl) {
        this.mPlayUrl = playUrl;
    }

    /**
     * 播放url
     *
     * @param playUrl 播放url
     */
    public void setPlayUrl(String playUrl) {
        this.mPlayUrl = playUrl == null ? null : Uri.parse(playUrl);
    }

    /**
     * 初始化播放器
     */
    private void initPlayer() {
        DefaultRenderersFactory defaultRenderersFactory = new DefaultRenderersFactory(mContext)
                //设置如果解码器初始化失败，是否启用回退到低优先级解码器。
                // 这可能导致使用比主解码器效率更低或更慢的解码器
                .setEnableDecoderFallback(true)
                //设置视频渲染器可以尝试无缝加入正在进行的播放的最大持续时间
                .setAllowedVideoJoiningTimeMs(10000)
                //允许使用扩展渲染器。扩展渲染器索引在相同类型的核心渲染器之后。因此，偏好第一个合适的渲染器的｛@link TrackSelector｝将倾向于使用核心渲染器而不是扩展渲染器，因为两者都能够播放给定的曲目
                .setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_ON);
        mPlayer = new ExoPlayer.Builder(mContext, defaultRenderersFactory)
                .build();
        mPlayer.addListener(mPlayerListener);
        mPlayer.setVideoTextureView(mTextureView);
        //打印日志
        if (LogUtils.isDebug()) {
            mPlayer.addAnalyticsListener(new EventLogger());
        }
    }

    private final ZDefaultPlayerListener mPlayerListener = new ZDefaultPlayerListener() {
        @Override
        public void onPlaybackStateChanged(int playbackState) {
            super.onPlaybackStateChanged(playbackState);
        }

        @Override
        public void onPlayerError(PlaybackException error) {
            super.onPlayerError(error);
        }
    };

    /**
     * 开始播放
     */
    public void startPlay() {
        if (mPlayer == null) {
            initPlayer();
        }

        //媒体项
        MediaItem mediaItem = new MediaItem.Builder()
                .setUri(mPlayUrl)
                .build();

        DefaultHttpDataSource.Factory httpDataSourceFactory = new DefaultHttpDataSource.Factory()
                .setConnectTimeoutMs(5_000)
                .setReadTimeoutMs(10_000)
                .setAllowCrossProtocolRedirects(true)
                .setKeepPostFor302Redirects(true);
//                .setTransferListener(new ZDefaultTransferListener());
        //HLS片段提取工厂
        int flag=DefaultTsPayloadReaderFactory.FLAG_IGNORE_AAC_STREAM | DefaultTsPayloadReaderFactory.FLAG_DETECT_ACCESS_UNITS;
//        int flag = DefaultTsPayloadReaderFactory.FLAG_DETECT_ACCESS_UNITS;
        DefaultHlsExtractorFactory defaultHlsExtractorFactory = new DefaultHlsExtractorFactory(flag, true);

        //hls媒体源工厂
        HlsMediaSource.Factory hlsMediaSourceFactory = new HlsMediaSource.Factory(httpDataSourceFactory);
        hlsMediaSourceFactory.setExtractorFactory(defaultHlsExtractorFactory);
        HlsMediaSource mediaSource = hlsMediaSourceFactory.createMediaSource(mediaItem);
        mPlayer.setMediaSource(mediaSource);
        mPlayer.prepare();
        //自动开始播放
        mPlayer.play();
//        mPlayer.seekToDefaultPosition();
        LogUtils.d(TAG, "开始播放");

    }


    /**
     * 停止播放
     */
    public void stopPlay() {
        if (mPlayer != null) {
            LogUtils.d(TAG, "停止播放:" + ZExoUtils.getPlaybackStateString(mPlayer.getPlaybackState()));
            mPlayer.stop();
        }
    }

    /**
     * 暂停播放
     */
    public void pausePlay() {
        if (mPlayer != null) {
            LogUtils.d(TAG, "暂停播放:" + ZExoUtils.getPlaybackStateString(mPlayer.getPlaybackState()));
            mPlayer.pause();
        }
    }

    /**
     * 恢复播放
     */
    public void resumePlay() {
        if (mPlayer != null) {
            LogUtils.d(TAG, "恢复播放:" + ZExoUtils.getPlaybackStateString(mPlayer.getPlaybackState()));
            mPlayer.play();
        }
    }

    /**
     * 定位到指定位置播放
     *
     * @param positionMs 毫秒
     */
    public void seekTo(long positionMs) {
        if (mPlayer != null) {
            mPlayer.seekTo(positionMs);
        }
    }

    /**
     * 获取播放进度 单位毫秒
     *
     * @return 播放进度
     */
    public long getCurrentPosition() {
        return mPlayer != null ? mPlayer.getCurrentPosition() : 0;
    }

    /**
     * 释放资源
     */
    public void release() {
        if (mPlayer != null) {
            LogUtils.d(TAG, "release:释放资源:" + mPlayer);
            mPlayer.removeListener(mPlayerListener);
            mPlayer.release();
            mPlayer = null;
        }
    }


}
